package com.qupai.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qupai.constant.MessageConstant;
import com.qupai.context.BaseContext;
import com.qupai.dto.*;
import com.qupai.entity.*;
import com.qupai.exception.OrderBusinessException;
import com.qupai.exception.ShoppingCartBusinessException;
import com.qupai.exception.UserInformationException;
import com.qupai.mapper.*;
import com.qupai.result.PageResult;
import com.qupai.service.PtOrderService;
import com.qupai.service.PtShoppingCartService;
import com.qupai.vo.PtOrderPaymentVO;
import com.qupai.vo.PtOrderStatisticsVO;
import com.qupai.vo.PtOrderSubmitVO;
import com.qupai.vo.PtOrderVO;
import com.qupai.websocket.WebSocketServer;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor
public class PtOrderServiceImpl extends ServiceImpl<PtOrderMapper,PtOrders> implements PtOrderService {

    private final PtShoppingCartMapper shoppingCartMapper;
    private final UserMapper userMapper;
    private final PtOrderMapper orderMapper;
    private final PtOrderDetailMapper orderDetailMapper;
    private final PtPrizeMapper prizesMapper;
    private final WebSocketServer webSocketServer;
    private final PtShoppingCartService shoppingCartService;

    /**
     * 用户下单
     */
    @Override
    @Transactional//事务注解
    public PtOrderSubmitVO submitOrder(PtOrdersSubmitDTO ordersSubmitDTO) {
        // 处理业务异常(购物车数据为空)
        PtShoppingCart shoppingCart = new PtShoppingCart();
        Long userId = BaseContext.getCurrentId();
        shoppingCart.setUserId(userId);

        List<Long> shoppingCartIds = ordersSubmitDTO.getShoppingCartIds();
        List<PtShoppingCart> shoppingCartList = new ArrayList<>();

        for (Long shoppingCartId : shoppingCartIds) {
            shoppingCart.setId(shoppingCartId);
            // 每次循环中查询对应ID的购物车数据
//            List<ShoppingCart> list = shoppingCartMapper.selectByUserIdAndShoppingCartId(shoppingCart);
            QueryWrapper<PtShoppingCart>wrapper=new QueryWrapper<>();
            wrapper.lambda()
                    .eq(PtShoppingCart::getUserId,userId)
                    .eq(PtShoppingCart::getId,shoppingCartId);
            List<PtShoppingCart> list = shoppingCartMapper.selectList(wrapper);
            // 将查询到的购物车数据添加到列表中
            shoppingCartList.addAll(list);
        }
        //购物车为空
        if (shoppingCartList.isEmpty()){
            throw new ShoppingCartBusinessException(MessageConstant.SHOPPING_CART_IS_NULL);
        }

        //在奖品表中更新奖品库存,和判断商品是否临时下架
        for (PtShoppingCart cart : shoppingCartList){
            Long prizesId=cart.getPrizesId();
            PtPrize prizes=prizesMapper.selectById(prizesId);

            //判断商品是否临时下架
            if (prizes.getStatus()==0){
                throw new ShoppingCartBusinessException(MessageConstant.PRIZES_IS_TEMPORARY_OFF_THE_SHELF);
            }

            //奖品未下单前的库存
            Long prizesStock = prizes.getStock();
            //购物车中奖品数量
            Long cartNumber = cart.getNumber();

            if (prizesStock<cartNumber){
                throw new ShoppingCartBusinessException(MessageConstant.PRIZES_STOCK_IS_NOT_ENOUGH);
            }
            //更新
            prizes.setStock(prizesStock-cartNumber);
            prizesMapper.updateById(prizes);
        }

        //插入数据
        //向订单表插入数据
        PtOrders orders=new PtOrders();
        BeanUtils.copyProperties(ordersSubmitDTO,orders);
        orders.setOrderTime(LocalDateTime.now());
        orders.setPayStatus(Orders.UN_PAID);
        orders.setStatus(Orders.PENDING_PAYMENT);
        //订单号使用当前时间的时间戳转为字符串的值
        orders.setNumber(String.valueOf(System.currentTimeMillis()));
        //用户id
        orders.setUserId(userId);

        //获取当前用户的手机号
        User user=userMapper.selectById(userId);
        //检查用户那些信息是否完善
        if (user.getPhone()==null||user.getPhone().equals("")||
                user.getCollegesId()==null||user.getCollegesId().equals("")||
                user.getMajor()==null||user.getMajor().equals("")||
                user.getClassName()==null||user.getClassName().equals("")||
                user.getStudentId()==null||user.getStudentId().equals("")){
            throw new UserInformationException(MessageConstant.USER_INFO_NOT_COMPLETE);
        }
        orders.setUserName(user.getName());
        orders.setPhone(user.getPhone());
        orders.setCollegesId(user.getCollegesId());
        orders.setMajor(user.getMajor());
        orders.setClassname(user.getClassName());

        //向订单表插入数据
        orderMapper.insert(orders);

        List<PtOrderDetail> orderDetailList =new ArrayList<>();
        //向订单明细表插入n条数据
        for (PtShoppingCart cart : shoppingCartList){
            System.out.println("cart: "+cart);
            PtOrderDetail orderDetail=new PtOrderDetail();//订单明细
            BeanUtils.copyProperties(cart,orderDetail);
            System.out.println("PtOrderDetail: "+orderDetail);
            orderDetail.setOrderId(orders.getId());//设置当前订单明细关联的订单id
            orderDetailList.add(orderDetail);
        }

        System.out.println("PtOrderDetailList: "+orderDetailList);

        //批量插入
        orderDetailMapper.insertBatch(orderDetailList);

        //按提交奖品去支付的奖品id集合和用户id批量删除购物车数据
        for (Long shoppingCartId : shoppingCartIds) {
            //根据用户id和购物车id删除购物车中的奖品
            QueryWrapper<PtShoppingCart> wrapper=new QueryWrapper<>();
            wrapper.lambda()
                    .eq(PtShoppingCart::getUserId,userId)
                    .eq(PtShoppingCart::getId,shoppingCartId);
            shoppingCartMapper.delete(wrapper);
        }

        PtOrderSubmitVO orderSubmitVO = PtOrderSubmitVO.builder()
                .id(orders.getId())
                .orderTime(orders.getOrderTime())
                .orderNumber(orders.getNumber())
                .orderAmount(orders.getAmount())
                .build();

        System.out.println("PtOrderSubmitVO: "+orderSubmitVO);

        return orderSubmitVO;
    }

    /**
     * 订单支付
     */
    @Override
    @Transactional//事务注解
    public PtOrderPaymentVO payment(PtOrdersPaymentDTO ordersPaymentDTO) {
        // 当前登录用户id
        Long userId = BaseContext.getCurrentId();
        User user = userMapper.selectById(userId);

        // 获取用户当前积分
        BigDecimal walletCommon = user.getWalletCommon();
        //查询该订单下所有奖品所需积分
        //订单号和用户id精确查
        QueryWrapper<PtOrders>wrapper=new QueryWrapper<>();
        wrapper.lambda()
                .eq(PtOrders::getId,ordersPaymentDTO.getId())
                .eq(PtOrders::getUserId,userId);
        PtOrders orders=orderMapper.selectOne(wrapper);
        BigDecimal amount = orders.getAmount();
        Integer payStatus = orders.getPayStatus();

        // 检查订单状态是否为未支付
        if(payStatus!=0){
            //订单支付状态异常，可能为已支付或者已退款
            throw new OrderBusinessException(MessageConstant.ORDERS_PAY_STATUS_ABNORMAL);
        }

        if(walletCommon.compareTo(amount)==-1){
            //积分不足兑换此订单
            throw new OrderBusinessException(MessageConstant.AMOUNT_IS_LESS_ORDERS_PAY);
        }

        // 扣除用户积分
        //用户积分减去所需积分amount
        walletCommon=walletCommon.subtract(amount);

        // 更新用户积分
        user.setWalletCommon(walletCommon);
        userMapper.updateById(user);

        //修改订单状态
        Integer OrderPaidStatus = Orders.PAID;//支付状态，已支付
        Integer OrderStatus = Orders.TO_BE_CONFIRMED;  //订单状态，待接单
        LocalDateTime checkout_time = LocalDateTime.now();//更新支付时间
        //更新订单状态
        orders.setPayStatus(OrderPaidStatus);
        orders.setStatus(OrderStatus);
        orders.setCheckoutTime(checkout_time);
        orderMapper.updateById(orders);
        // 给orderPaymentVO赋值
        PtOrderPaymentVO orderPaymentVO=new PtOrderPaymentVO();
        //订单号和用户id精确查
        QueryWrapper<PtOrders>wrapper2=new QueryWrapper<>();
        wrapper2.lambda()
                .eq(PtOrders::getId,ordersPaymentDTO.getId())
                .eq(PtOrders::getUserId,userId);
        orderMapper.selectOne(wrapper2);
        BeanUtils.copyProperties(orders,orderPaymentVO);

        //通过websocket向客户端浏览器推送消息 type orderId content
        Map<String, Object> map=new HashMap<>();
        map.put("type",1);//1表示来单提醒，2表示提醒管理员查看订单
        map.put("PtorderId",orders.getId());//订单id
        map.put("content","订单号："+orders.getNumber());//订单号


        String json = JSON.toJSONString(map);
        webSocketServer.sendToAllClient(json);

        //返回VO
        return orderPaymentVO;
    }

    /**
     * 历史订单查询
     *
     * @param pageNum 页码
     * @param pageSize 页码数据数量
     * @param status   订单状态 1待付款 2待接单 3已接单 4已完成 5已取消
     */
    @Override
    public PageResult pageQueryUser(Long pageNum, Long pageSize, Integer status) {

        // 1.构建条件
        // 1.1.分页条件
        Page<PtOrders> page = Page.of(pageNum, pageSize);

        PtOrdersPageQueryDTO ordersPageQueryDTO=new PtOrdersPageQueryDTO();
        ordersPageQueryDTO.setUserId(BaseContext.getCurrentId());
        ordersPageQueryDTO.setStatus(status);

        // 分页条件查询
        Page<PtOrders>p=lambdaQuery()
                .like(ordersPageQueryDTO.getNumber()!=null,PtOrders::getNumber,ordersPageQueryDTO.getNumber())
                .like(ordersPageQueryDTO.getPhone()!=null,PtOrders::getPhone,ordersPageQueryDTO.getPhone())
                .eq(ordersPageQueryDTO.getUserId()!=null,PtOrders::getUserId,ordersPageQueryDTO.getUserId())
                .eq(ordersPageQueryDTO.getStatus()!=null,PtOrders::getStatus,ordersPageQueryDTO.getStatus())
                .ge(ordersPageQueryDTO.getBeginTime()!=null,PtOrders::getOrderTime,ordersPageQueryDTO.getBeginTime())
                .le(ordersPageQueryDTO.getEndTime()!=null,PtOrders::getOrderTime,ordersPageQueryDTO.getEndTime())
                //按订单时间排序
                .orderByDesc(PtOrders::getOrderTime)
                .page(page);

        List<PtOrders> ordersList = p.getRecords();
        List<PtOrderVO> list = new ArrayList<>();

        // 查询出订单明细，并封装入OrderVO进行响应
        if (ordersList!=null&& !ordersList.isEmpty()){
            for (PtOrders orders : ordersList) {
                Long orderId = orders.getId();//订单id

                // 查询订单明细
                QueryWrapper<PtOrderDetail> OrderDetailWrapper = new QueryWrapper<>();
                OrderDetailWrapper.lambda().eq(PtOrderDetail::getOrderId, orderId);
                List<PtOrderDetail> orderDetails =orderDetailMapper.selectList(OrderDetailWrapper);
                PtOrderVO orderVO = new PtOrderVO();
                BeanUtils.copyProperties(orders, orderVO);
                orderVO.setOrderDetailList(orderDetails);

                list.add(orderVO);
            }
        }

        return new PageResult(p.getTotal(),p.getPages(),list);
    }

    /**
     * 查询订单详情
     */
    @Override
    public PtOrderVO details(Long id) {
        PtOrders orders = orderMapper.selectById(id);

        //查询订单详细
        QueryWrapper<PtOrderDetail> OrderDetailWrapper = new QueryWrapper<>();
        OrderDetailWrapper.lambda().eq(PtOrderDetail::getOrderId, orders.getId());
        List<PtOrderDetail> orderDetails =orderDetailMapper.selectList(OrderDetailWrapper);

        // 将该订单及其详情封装到OrderVO并返回
        PtOrderVO orderVO = new PtOrderVO();
        BeanUtils.copyProperties(orders, orderVO);
        orderVO.setOrderDetailList(orderDetails);
        return orderVO;
    }

    /**
     * 再来一单
     */
    @Override
    public void repetition(Long id) {
        // 查询当前用户id
        Long userId = BaseContext.getCurrentId();

        // 根据订单id查询当前订单详情
//        List<OrderDetail> orderDetailList = orderDetailMapper.getByOrderId(id);
        QueryWrapper<PtOrderDetail> OrderDetailWrapper = new QueryWrapper<>();
        OrderDetailWrapper.lambda().eq(PtOrderDetail::getOrderId, id);
        List<PtOrderDetail> orderDetailList =orderDetailMapper.selectList(OrderDetailWrapper);

        // 将订单详情对象转换为购物车对象
        List<PtShoppingCart> shoppingCartList = orderDetailList.stream().map(x -> {
            PtShoppingCart shoppingCart = new PtShoppingCart();

            // 将原订单详情里面的奖品信息重新复制到购物车对象中
            BeanUtils.copyProperties(x, shoppingCart, "id");//id作为属性过滤器，表示只不复制id属性。
            shoppingCart.setUserId(userId);
            shoppingCart.setCreateTime(LocalDateTime.now());

            return shoppingCart;
        }).collect(Collectors.toList());

        // 将购物车对象批量添加到数据库
        //用mapper的方法
//        shoppingCartMapper.insertBatch(shoppingCartList);
        //用service的方法
        shoppingCartService.saveBatch(shoppingCartList);
    }

    /**
     * 订单分页查询
     */
    @Override
    public PageResult conditionSearch(PtOrdersPageQueryDTO ordersPageQueryDTO) {
        // 构建分页条件
        Page<PtOrders>page=Page.of(ordersPageQueryDTO.getPageNo(),ordersPageQueryDTO.getPageSize());

        // 分页条件查询
        Page<PtOrders>p=lambdaQuery()
                .like(ordersPageQueryDTO.getNumber()!=null,PtOrders::getNumber,ordersPageQueryDTO.getNumber())
                .like(ordersPageQueryDTO.getPhone()!=null,PtOrders::getPhone,ordersPageQueryDTO.getPhone())
                .eq(ordersPageQueryDTO.getUserId()!=null,PtOrders::getUserId,ordersPageQueryDTO.getUserId())
                .eq(ordersPageQueryDTO.getStatus()!=null,PtOrders::getStatus,ordersPageQueryDTO.getStatus())
                .ge(ordersPageQueryDTO.getBeginTime()!=null,PtOrders::getOrderTime,ordersPageQueryDTO.getBeginTime())
                .le(ordersPageQueryDTO.getEndTime()!=null,PtOrders::getOrderTime,ordersPageQueryDTO.getEndTime())
                //按订单时间排序
                .orderByDesc(PtOrders::getOrderTime)
                .page(page);

        List<PtOrders> ordersList = p.getRecords();

        // 循环遍历第二步结果 查询订单明细
        List<PtOrderVO> orderVOList = new ArrayList<>();

        for (PtOrders orders : ordersList) {
            //查询订单详细
            QueryWrapper<PtOrderDetail> OrderDetailWrapper = new QueryWrapper<>();
            OrderDetailWrapper.lambda().eq(PtOrderDetail::getOrderId, orders.getId());
            List<PtOrderDetail> orderDetailList =orderDetailMapper.selectList(OrderDetailWrapper);
            //封装VO对象
            PtOrderVO orderVO=new PtOrderVO();
            BeanUtils.copyProperties(orders,orderVO);

            StringBuilder prizesName= new StringBuilder();//拼接奖品信息
            for (PtOrderDetail orderDetail : orderDetailList) {
                prizesName.append(orderDetail.getName()).append("*").append(orderDetail.getNumber()).append(";");
            }

            //封装VO
            orderVO.setOrderPrizes(prizesName.toString());

            orderVOList.add(orderVO);

        }
        return new PageResult(p.getTotal(),p.getPages(),orderVOList);
    }

    /**
     * 各个状态的订单数量统计
     */
    @Override
    public PtOrderStatisticsVO statistics() {

        // 根据状态，分别查询出待接单、已接单的的订单数量
        // 使用MyBatis Plus的count方法进行统计
        QueryWrapper<PtOrders>wrapper=new QueryWrapper<>();
        wrapper.lambda()
                .eq(PtOrders::getStatus, Orders.TO_BE_CONFIRMED);
        Long toBeConfirmed =orderMapper.selectCount(wrapper);

        wrapper.lambda()
                .eq(PtOrders::getStatus, Orders.CONFIRMED);
        Long confirmed =orderMapper.selectCount(wrapper);

        // 将查询出的数据封装到orderStatisticsVO中响应
        PtOrderStatisticsVO orderStatisticsVO = new PtOrderStatisticsVO();
        orderStatisticsVO.setToBeConfirmed(toBeConfirmed);
        orderStatisticsVO.setConfirmed(confirmed);
        return orderStatisticsVO;
    }

    /**
     * 接单
     */
    @Override
    public void confirm(PtOrdersConfirmDTO ordersConfirmDTO) {
        if (!ordersConfirmDTO.getStatus().equals(Orders.TO_BE_CONFIRMED)){
            //非待接单的奖品不能接单
            throw new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR);
        }
        PtOrders orders = PtOrders.builder()
                .id(ordersConfirmDTO.getId())
                .status(Orders.CONFIRMED)
                .build();
        orderMapper.updateById(orders);
    }

    /**
     * 拒单
     */
    @Override
    @Transactional//事务注解
    public void rejection(PtOrdersRejectionDTO ordersRejectionDTO) {
        //根据id查询订单
        PtOrders ordersRJ=orderMapper.selectById(ordersRejectionDTO.getId());

        // 订单只有存在且状态为2（待接单）才可以拒单
        if (ordersRJ == null || !ordersRJ.getStatus().equals(Orders.TO_BE_CONFIRMED)) {
            throw new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR);
        }

        //支付状态
        Integer payStatus = ordersRJ.getPayStatus();
        if (payStatus .equals(Orders.PAID) ) {
            //用户已支付，需要退款
            BigDecimal amount = ordersRJ.getAmount();

            User user =userMapper.selectById(BaseContext.getCurrentId());

            if (ordersRJ.getPayMethod()==3){
                //按照该方式退款
                BigDecimal returnPay=user.getWalletCommon().add(amount);
                System.out.println("pay: "+returnPay);
                user.setWalletCommon(returnPay);
                userMapper.updateById(user);
            }else{
                //尚未支持该支付方式
                throw new OrderBusinessException("THIS_PAY_METHOD_IS_NOT_YET_SUPPORTED");
            }
            log.info("申请退款成功");
        }
        // 拒单需要退款，根据订单id更新订单状态、拒单原因、取消时间
        PtOrders orders = new PtOrders();
        orders.setId(ordersRJ.getId());
        orders.setStatus(Orders.CANCELLED);
        orders.setPayStatus(Orders.REFUND);
        orders.setRejectionReason(ordersRejectionDTO.getRejectionReason());
        orders.setCancelTime(LocalDateTime.now());

        orderMapper.updateById(orders);
    }

    /*
    * 用户取消订单
    * */
    @Override
    public void userCancelById(Long id){
        // 根据id查询订单
        PtOrders ordersDB = orderMapper.selectById(id);

        // 校验订单是否存在
        if (ordersDB == null) {
            throw new OrderBusinessException(MessageConstant.ORDER_NOT_FOUND);
        }

        //订单状态 1待付款 2待接单 3已接单 4已完成 5已取消
        if (ordersDB.getStatus() > 2) {
            throw new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR);
        }

        PtOrders orders = new PtOrders();
        orders.setId(ordersDB.getId());

        //处于未接单状态要进行退款
        if(ordersDB.getStatus().equals(Orders.TO_BE_CONFIRMED)){
            //退款操作
            BigDecimal dbAmount = ordersDB.getAmount();
            Long userId = ordersDB.getUserId();
            User user = userMapper.selectById(userId);

            // 退款，用户钱包增加
            user.setWalletVolunteer(user.getWalletVolunteer().add(dbAmount));
            userMapper.updateById(user);

            //支付状态修改为 退款
            orders.setPayStatus(Orders.REFUND);
        }
        // 更新订单状态、取消原因、取消时间
        orders.setStatus(Orders.CANCELLED);
        orders.setCancelReason("用户取消");
        orders.setCancelTime(LocalDateTime.now());
        orderMapper.updateById(orders);
    }

    /**
     * 取消订单
     */
    @Override
    public void cancel(PtOrdersCancelDTO ordersCancelDTO) {
        // 根据id查询订单
        PtOrders ordersDB = orderMapper.selectById(ordersCancelDTO.getId());

        //支付状态
        Integer payStatus = ordersDB.getPayStatus();
        if (payStatus .equals(Orders.PAID) ) {
            //用户已支付，需要退款
            BigDecimal amount = ordersDB.getAmount();

            User user =userMapper.selectById(BaseContext.getCurrentId());

            //判断是什么支付方式。3，志愿；4，普通
            if (ordersDB.getPayMethod()==4){
                //普通积分支付,按照该方式退款
                BigDecimal returnPay=user.getWalletCommon().add(amount);
                System.out.println("pay: "+returnPay);
                user.setWalletCommon(returnPay);
                userMapper.updateById(user);
            }else{
                //尚未支持该支付方式
                throw new OrderBusinessException("THIS_PAY_METHOD_IS_NOT_YET_SUPPORTED");
            }
            log.info("申请退款成功");
        }

        // 管理端取消订单需要退款，根据订单id更新订单状态、取消原因、取消时间
        PtOrders orders = new PtOrders();
        orders.setId(ordersCancelDTO.getId());
        orders.setStatus(Orders.CANCELLED);
        orders.setPayStatus(Orders.REFUND);
        orders.setCancelReason(ordersCancelDTO.getCancelReason());
        orders.setCancelTime(LocalDateTime.now());
        orderMapper.updateById(orders);
        log.info("订单取消成功");

    }

    /**
     * 完成订单
     */
    @Override
    public void complete(Long id) {
        // 根据id查询订单
        PtOrders ordersDB = orderMapper.selectById(id);

        // 校验订单是否存在，并且状态为3已接单
        if (ordersDB == null || !ordersDB.getStatus().equals(Orders.CONFIRMED)) {
            throw new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR);
        }

        PtOrders orders = new PtOrders();
        orders.setId(ordersDB.getId());
        // 更新订单状态,状态转为完成
        orders.setStatus(Orders.COMPLETED);
        orders.setCompleteTime(LocalDateTime.now());

        orderMapper.updateById(orders);
        log.info("订单完成成功");
    }
}
